package org.dftproject.genesis.ui.figures;

import java.util.Iterator;

import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.Cursors;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FocusEvent;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.KeyEvent;
import org.eclipse.draw2d.KeyListener;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.MouseEvent;
import org.eclipse.draw2d.MouseListener;
import org.eclipse.draw2d.MouseMotionListener;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.StackLayout;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.resource.JFaceColors;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;

public class HyperlinkFigure extends Figure {

	public static final Color inactiveColor = JFaceColors.getHyperlinkText(null);
	public static final Color activeColor = JFaceColors.getActiveHyperlinkText(null);

	private boolean hover;
	private boolean alwaysUnderline = true;
	private Object data;
	
	private final Label label;

	public HyperlinkFigure() {
		this(null, null);
	}
	
	public HyperlinkFigure(String text) {
		this(text, null);
	}

	public HyperlinkFigure(String text, Image icon) {
		setCursor(Cursors.HAND);
		setFocusTraversable(true);
		addListeners();
		
		setLayoutManager(new StackLayout());
		setBorder(new MarginBorder(1));

		label = new Label(text, icon) {

			@Override
			protected void paintFigure(Graphics graphics) {
				if (isOpaque())
					super.paintFigure(graphics);
				Rectangle bounds = getBounds();
				graphics.translate(bounds.x, bounds.y);
				Image icon = getIcon();
				if (icon != null)
					graphics.drawImage(icon, getIconLocation());
				Point location = getTextLocation();
				graphics.drawText(getSubStringText(), location);
				if (alwaysUnderline || hover) {
					Dimension size = getTextSize();
					graphics.drawLine(location.x, location.y + size.height - 1, location.x + size.width, location.y + size.height - 1);
				}
				graphics.translate(-bounds.x, -bounds.y);
			}
			
		};
		label.setIconTextGap(5);
		label.setLabelAlignment(PositionConstants.CENTER);
		label.setTextPlacement(PositionConstants.EAST);
		add(label);
	}

	public void setText(String text) {
		label.setText(text);
	}

	public void setIcon(Image icon) {
		label.setIcon(icon);
	}
	
	@Override
	public void handleFocusGained(FocusEvent event) {
		super.handleFocusGained(event);
		repaint();
	}

	@Override
	public void handleFocusLost(FocusEvent event) {
		super.handleFocusLost(event);
		repaint();
	}

	protected void addListeners() {
		MouseTracker tracker = new MouseTracker();
		addMouseMotionListener(tracker);
		addMouseListener(tracker);
		addKeyListener(new KeyListener.Stub() {

			@Override
			public void keyReleased(KeyEvent ke) {
				if (ke.keycode == SWT.CR)
					handleActivate(SWT.NONE);
			}
			
		});
	}

	protected boolean getHover() {
		return hover;
	}

	protected void setHover(boolean hover) {
		this.hover = hover;
	}

	@Override
	public void paint(Graphics graphics) {
		graphics.setForegroundColor(hover || hasFocus() ? activeColor : inactiveColor);
		super.paint(graphics);
	}

	@Override
	protected void paintBorder(Graphics graphics) {
		super.paintBorder(graphics);
		if (hasFocus()) {
			graphics.setForegroundColor(ColorConstants.black);
			graphics.setBackgroundColor(ColorConstants.white);
			graphics.drawFocus(getBounds().getResized(-1, -1));
		}
	}

	public void addHyperlinkListener(IHyperlinkListener listener) {
		addListener(IHyperlinkListener.class, listener);
	}

	public void removeHyperlinkListener(IHyperlinkListener listener) {
		removeListener(IHyperlinkListener.class, listener);
	}

	protected void handleActivate(int state) {
		Iterator<?> iter = getListeners(IHyperlinkListener.class);
		while (iter.hasNext())
			((IHyperlinkListener) iter.next()).linkActivated(data, state);
	}

	protected class MouseTracker extends MouseMotionListener.Stub implements MouseListener {

		private boolean mouseDown;

		public void mousePressed(MouseEvent me) {
			if (me.button == 1) {
				me.consume();
	
				mouseDown = true;
			}
		}

		public void mouseReleased(MouseEvent me) {
			if (mouseDown && me.button == 1) {	
				if (getBounds().contains(me.getLocation()))
					handleActivate(me.getState());
				
				mouseDown = false;
			}
		}
		
		public void mouseDoubleClicked(MouseEvent me) {
		}

		@Override
		public void mouseEntered(MouseEvent me) {
			setHover(true);
			repaint();
		}

		@Override
		public void mouseExited(MouseEvent me) {
			setHover(false);
			repaint();
		}

		@Override
		public void mouseDragged(MouseEvent me) {
			setHover(getBounds().contains(me.getLocation()));
			repaint();
		}

	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	public boolean isAlwaysUnderline() {
		return alwaysUnderline;
	}

	public void setAlwaysUnderline(boolean alwaysUnderline) {
		this.alwaysUnderline = alwaysUnderline;
	}

}
